#include "timeit.h"

#include <ctime>
#include <cassert>
#include <stdexcept>

#include "exception.h"


namespace evm {

double time() {
    timespec ts;
    if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
        assert(errno == EINVAL);
        throw std::invalid_argument("CLOCK_MONOTONIC is not supported");
    }
    return ts.tv_sec + ts.tv_nsec / 1e6 * 1.0e-3;  // correct to three decimal places
}

Timeit::Timeit() : start_at(time()) {}

void sleep(double seconds) {
    ::timespec req, rem;
    req.tv_sec = static_cast<time_t>(seconds);
    req.tv_nsec = static_cast<long>((seconds - req.tv_sec) * 1e9);
    while (true) {
        if (::clock_nanosleep(CLOCK_MONOTONIC, 0, &req, &rem) == 0)
            return;

        if (errno != EINTR)
            throw_system_error("Call clock_nanosleep failed");

        req = rem;
        continue;
    }
}

double Timeit::get() {
    return time() - start_at;
}

std::random_device RandomSleep::rd;
std::default_random_engine RandomSleep::re{rd()};

}
